Recently released data from Statistics Canada allows us to explore demographic trends in the age make-up of the Canadian population. The trend is clear: Canada is getting old.
In this chart-blog, we will take a look at population by age group – both across regions and over time – and how median age has evolved. (Spoiler: It’s risen. A lot!)
For those interested in how to create these graphs in R, all the code can be seen by clicking the code button running along the side of each section.
data <- get_cansim(17100005) %>% normalize_cansim_values()
age.keep <- c(
"0 to 4 years",
"5 to 9 years",
"10 to 14 years",
"15 to 19 years",
"20 to 24 years",
"25 to 29 years",
"30 to 34 years",
"35 to 39 years",
"40 to 44 years",
"45 to 49 years",
"50 to 54 years",
"55 to 59 years",
"60 to 64 years",
"65 to 69 years",
"70 to 74 years",
"75 to 79 years",
"80 to 84 years",
"85 to 89 years",
"90 to 94 years",
"95 to 99 years",
"100 years and over"
)
These charts show the share of total population in each age group, separately for men (blue) and women (red). What was once known as an age pyramid now looks more like an ominous age torpedo!
df <- data %>%
mutate(Year=as.integer(REF_DATE)) %>%
filter(Sex!="Both sexes",
`Age group` %in% age.keep,
Year %in% c(1971,2018)) %>%
group_by(Year,GEO) %>%
mutate(`Age share` = VALUE/sum(VALUE))
df$`Age group` <- factor(df$`Age group`, levels=age.keep)
twoplot <- function(p){
ggplot()+
geom_col(data=df %>% filter(GEO==p,Sex=="Males"),
aes(`Age group`,`Age share`),fill="#2b83ba")+
geom_col(data=df %>% filter(GEO==p,Sex=="Females"),
aes(`Age group`,-`Age share`),fill="#d7191c")+
annotate("text",x=21,y=-.02,label="Women",family="Lato",size=4,color="#d7191c")+
annotate("text",x=21,y=.02,label="Men",family="Lato",size=4,color="#2b83ba")+
facet_wrap(~Year)+
coord_flip()+
scale_y_continuous(breaks=c(-.05,0,.05),
label=scales::percent)+
theme_tufte(14,"Lato")+
theme(axis.ticks = element_blank(),
plot.caption = element_text(size=8))+
labs(y="Share of population",x="",
title=paste0("Population by age group, ",p),
caption="Source: Statistics Canada NDM 17-10-0005\nChart by @bcshaffer")
}
twoplot("Canada")
twoplot("British Columbia")
twoplot("Alberta")
twoplot("Saskatchewan")
twoplot("Manitoba")
twoplot("Ontario")
twoplot("Quebec")
twoplot("New Brunswick")
twoplot("Prince Edward Island")
twoplot("Nova Scotia")
twoplot("Newfoundland and Labrador")
twoplot("Yukon")
Another way to see the aging of the population is to look at how the median age has changed over the years. Here’s median age for Canada, from 1971 to 2018.
d.median <- data %>%
filter(`Age group`=="Median age") %>%
mutate(Year=as.integer(REF_DATE))
d.median.label <- d.median %>%
filter(Year %in% c(1971,2018),GEO=="Canada",Sex=="Both sexes")
ggplot(d.median %>% filter(GEO=="Canada"))+
geom_line(aes(Year,VALUE,color=Sex,linetype=Sex),size=1.2)+
geom_label(data=d.median.label,
aes(Year,VALUE,label=VALUE),
hjust=ifelse(d.median.label$Year==1971,1.1,-.1),
family="Lato")+
scale_x_continuous(limits=c(1970,2020))+
scale_linetype_discrete(name="")+
scale_color_manual(name="",values=c("Black","Red","Blue"))+
theme_hc(14,"Lato")+
theme(axis.ticks = element_blank(),
plot.caption=element_text(size=9))+
labs(y="",x="",
title="Median age in Canada, 1971 to 2018",
caption="Source: Statistics Canada NDM 17-10-0005\nChart by @bcshaffer")
short_prov <- c(
"British Columbia"="BC",
"Alberta"="AB",
"Saskatchewan"="SK",
"Manitoba"="MB",
"Ontario"="ON",
"Quebec"="QC",
"New Brunswick"="NB",
"Prince Edward Island"="PE",
"Nova Scotia"="NS",
"Newfoundland and Labrador"="NL",
"Yukon"="YT",
"Northwest Territories"="NT",
"Nunavut"="NU",
"Northwest Territories including Nunavut"="NTNU",
"Canada"="CAN")
d.median <- d.median %>%
mutate(GEO.abb=short_prov[GEO],
GEO.abb=factor(GEO.abb, levels=c("CAN","BC","AB","SK","MB","ON","QC","NB","PE","NS","NL","YT","NTNU","NT","NU")))
ggplot(d.median, aes(Year,VALUE,color=Sex))+
geom_line()+
scale_color_manual(name="",values=c("Black","Red","Blue"))+
scale_x_continuous(breaks=c(1970,1990,2010))+
facet_wrap(~GEO.abb)+
theme_hc(12,"Lato")+
labs(y="",x="",
title="Median age, 1971 to 2018")
I made an animated chart of the age pyramid and posted it on twitter:
Canadian population by age, 1971-2018. Follow the Baby Boomer Bulge!#cdnecon #cdnpoli pic.twitter.com/KStrjgg6Nh
— Blake Shaffer 📊 (@bcshaffer) January 25, 2019
This chart drew a lot of hits and a lot of commentary on twitter. Some noted how this shift in ages to a “top heavy pyramid” would put strains on pensions and health care costs:
Ultimately, do you think this causes any risks associated with things like Health Care, or CPP? Are they sustainable as this group both ages, and lives longer due to better modern medicine?
— Kevin Frankiw (@Franks_Five) January 25, 2019
Others noted how the animated chart allowed for a clear visual of the Baby Boomers over time and the emergence of the Echo Boom:
And by the end of the gif, you can even make out the baby boom echo
— Steve Niles (@SteveNilesCBC) January 25, 2019
And some astute observers commented on the dearth of population share for the Gen Xers:
We Gen-Xers are so nice and trim.
— Todd Babiak (@babiak) January 25, 2019
Anyways, here’s that animated chart with the code to make it using gganimate:
library(gganimate)
df2 <- data %>%
mutate(Year=as.integer(REF_DATE)) %>%
filter(Sex!="Both sexes",
`Age group` %in% age.keep) %>%
group_by(Year,GEO) %>%
mutate(`Age share` = VALUE/sum(VALUE))
df2$`Age group` <- factor(df2$`Age group`, levels=age.keep)
p <- ggplot()+
geom_col(data=df2 %>% filter(Sex=="Males",GEO=="Canada"),
aes(`Age group`,`Age share`),fill="#2b83ba")+
geom_col(data=df2 %>% filter(Sex=="Females",GEO=="Canada"),
aes(`Age group`,-`Age share`),fill="#d7191c")+
annotate("text",x=19,y=-.03,label="Women",family="Lato",size=6,color="#d7191c")+
annotate("text",x=19,y=.03,label="Men",family="Lato",size=6,color="#2b83ba")+
coord_flip()+
scale_y_continuous(breaks=c(-.06,-.03,0,.03,.06),
label=c("6%","3%","0%","3%","6%"))+
theme_tufte(14,"Lato")+
theme(axis.ticks = element_blank(),
plot.caption = element_text(size=8))+
labs(y="Share of population",x="Age group",
title=paste0("Canadian population by age, ","{frame_time}"),
caption="Source: Statistics Canada NDM 17-10-0005\nChart by @bcshaffer")+
transition_time(Year)+
ease_aes("linear")
animate(p, nframes = 100, fps = 3, end_pause = 30)
Happy charting!
- Blake